/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-unused-vars */
/* eslint-disable no-restricted-syntax */
import { useControlController, useNamespace } from '@ibiz-template/vue3-util';
import {
  computed,
  defineComponent,
  PropType,
  resolveComponent,
  VNode,
  h,
  onMounted,
  getCurrentInstance,
  ref,
  Ref,
} from 'vue';
import {
  IDEGantt,
  IDETBGroupItem,
  IDETBRawItem,
  IDETBUIActionItem,
  IDEToolbarItem,
  IDETreeColumn,
  IPanel,
} from '@ibiz/model-core';
import {
  IControlProvider,
  GanttController,
  IGanttNodeData,
  IButtonState,
  IButtonContainerState,
} from '@ibiz-template/runtime';
import { MenuItem } from '@imengyu/vue3-context-menu';
import dayjs from 'dayjs';
import {
  AllowDropType,
  NodeDropType,
} from 'element-plus/es/components/tree/src/tree.type';
import { findNodeData, formatNodeDropType } from '../tree/el-tree-util';
import './gantt.scss';

export const GanttControl = defineComponent({
  name: 'IBizGanttControl',
  props: {
    modelData: { type: Object as PropType<IDEGantt>, required: true },
    context: { type: Object as PropType<IContext>, required: true },
    params: { type: Object as PropType<IParams>, default: () => ({}) },
    provider: { type: Object as PropType<IControlProvider> },
    loadDefault: { type: Boolean, default: true },
    mdctrlActiveMode: { type: Number, default: undefined },
    singleSelect: { type: Boolean, default: undefined },
  },
  setup(props) {
    const c = useControlController<GanttController>(
      (...args) => new GanttController(...args),
    );

    const ganttRef: Ref<IData | undefined> = ref();

    // 是否初始化
    const isInited: Ref<boolean> = ref(false);
    const ns = useNamespace(`control-${c.model.controlType!.toLowerCase()}`);

    // 滑块移动
    const sliderMove = ref(false);

    const iBizRawItem = resolveComponent('IBizRawItem');
    const iBizIcon = resolveComponent('IBizIcon');

    let forbidClick: boolean = false;

    const selection: IGanttNodeData[] = [];

    const color = [
      'blue',
      'light-blue',
      'blue-cyan',
      'pink',
      'purple',
      'violet',
      'indigo',
      'cyan',
      'teal',
      'green',
      'light-green',
      'lime',
      'yellow',
      'amber',
      'orange',
      'grey',
      'sky-blue',
    ];

    // 动态加载gantt组件
    const app = getCurrentInstance()?.appContext.app;
    onMounted(() => {
      const importGantt = () => import('@ibiz-template-plugin/gantt');
      importGantt().then(value => {
        const defaltModule = value.default;
        app?.use(defaltModule);
        isInited.value = true;
      });
    });

    const getVarValue = (varName: string) => {
      const root = document.documentElement;
      return getComputedStyle(root).getPropertyValue(varName);
    };

    const ganttStyle = computed(() => {
      const style = {
        primaryColor:
          c.state.ganttStyle?.primaryColor ||
          getVarValue('--ibiz-color-primary'),
        textColor:
          c.state.ganttStyle?.textColor ||
          getVarValue('--ibiz-color-primary-text'),
      };
      return style;
    });

    const sliderColor = computed(() => {
      const nodeColor: IData = {};
      c.model.detreeNodes?.forEach((node, index) => {
        const colorIndex = index % color.length;
        nodeColor[node.id!] = `rgba(${getVarValue(
          `--ibiz-${color[colorIndex]}-0`,
        )}, 1)`;
      });
      return nodeColor;
    });

    /**
     * 部件是否在加载状态
     */
    const loading = computed(() => {
      if (c.state.isLoaded) {
        return c.state.isLoading;
      }
      return false;
    });

    /**
     * 实际呈现的数据
     */
    const data = computed(() => {
      if (!c.state.isLoaded) {
        return [];
      }
      return c.model.rootVisible
        ? c.state.rootNodes
        : c.state.rootNodes.reduce<IGanttNodeData[]>((result, nodeData) => {
            if (nodeData._children) {
              return result.concat(nodeData._children as IGanttNodeData[]);
            }
            return result;
          }, []);
    });

    /**
     * 实际绘制的表格列
     */
    const columns = computed(() => {
      const columnsModel: IDETreeColumn[] = [];
      c.state.columnStates.forEach(item => {
        const columnModel = c.columns[item.key]?.model;
        if (!item.hidden && columnModel) {
          columnsModel.push(columnModel);
        }
      });
      return columnsModel;
    });

    const locale = computed(() => {
      return ibiz.i18n.getLang().toLowerCase();
    });

    /**
     * 查找对应节点的布局面板
     *
     * @param {string} id
     * @return {*}  {(IPanel | undefined)}
     */
    const findNodeLayoutPanel = (id: string): IPanel | undefined => {
      let layoutPanel: IPanel | undefined;
      const nodeModel = c.getNodeModel(id);
      nodeModel?.controlRenders?.forEach(renderItem => {
        if (renderItem.renderType === 'LAYOUTPANEL') {
          layoutPanel = renderItem.layoutPanel;
        }
      });
      return layoutPanel;
    };

    /**
     * 多选时选中节点变更
     *
     * @param {boolean} state 当前复选框状态
     * @param {IGanttNodeData} item 当前数据
     */
    const onCheck = (state: boolean, item: IGanttNodeData) => {
      if (state) {
        selection.push(item);
      } else {
        const index = selection.findIndex(
          selected => selected._id === item._id,
        );
        if (index > -1) {
          selection.splice(index, 1);
        }
      }
      c.setSelection(selection);
    };

    /**
     * 节点单击事件
     *
     * @param {IGanttNodeData} nodeData
     * @return {*}
     */
    const onNodeClick = (nodeData: IGanttNodeData, evt: MouseEvent) => {
      if (forbidClick || sliderMove.value) {
        sliderMove.value = false;
        return;
      }

      c.onTreeNodeClick(nodeData, evt);
      forbidClick = true;
      setTimeout(() => {
        forbidClick = false;
      }, 200);
    };

    /**
     * 节点双击事件
     *
     * @param {IGanttNodeData} nodeData
     */
    const onNodeDbClick = (nodeData: IGanttNodeData) => {
      c.onDbTreeNodeClick(nodeData);
    };

    /**
     * 处理节点展开
     *
     * @param {IGanttNodeData} nodeData
     */
    const onNodeExpand = (nodeData: IGanttNodeData) => {
      c.onExpandChange(nodeData, true);
      if (nodeData && !nodeData._children) {
        c.refreshNodeChildren(nodeData);
      }
    };

    // 新建行
    c.evt.on('onNewRow', event => {
      const nodeData = event.row.data;
      ganttRef.value?.setExpand(nodeData);
    });

    /**
     * 处理节点折叠
     *
     * @param {IGanttNodeData} nodeData
     */
    const onNodeCollapse = (nodeData: IGanttNodeData) => {
      c.onExpandChange(nodeData, false);
    };

    /**
     * 是否允许拖入
     *
     * @param {IGanttNodeData} draggingNode
     * @param {IGanttNodeData} dropNode
     * @param {AllowDropType} type
     * @return {*}
     */
    const allowDrop = (
      draggingNode: IGanttNodeData,
      dropNode: IGanttNodeData,
      type: AllowDropType,
    ) => {
      const draggingNodeData = findNodeData(draggingNode._uuid, c)!;
      const dropNodeData = findNodeData(dropNode._uuid, c)!;
      const result = c.calcAllowDrop(draggingNodeData, dropNodeData, type);
      return result;
    };

    /**
     * 是否允许拖动
     *
     * @param {IGanttNodeData} draggingNode
     * @return {*}
     */
    const allowDrag = (draggingNode: IGanttNodeData) => {
      const nodeData = findNodeData(draggingNode._uuid, c)!;
      return c.calcAllowDrag(nodeData);
    };

    /**
     * 处理节点拖入事件
     *
     * @param {IGanttNodeData} draggingNode
     * @param {IGanttNodeData} dropNode
     * @param {NodeDropType} dropType
     */
    const handleDrop = (
      draggingNode: IGanttNodeData,
      dropNode: IGanttNodeData,
      dropType: NodeDropType,
    ) => {
      const draggingNodeData = findNodeData(
        draggingNode._uuid,
        c,
      ) as IGanttNodeData;
      const dropNodeData = findNodeData(dropNode._uuid, c) as IGanttNodeData;
      const type = formatNodeDropType(dropType);
      c.onNodeDrop(draggingNodeData, dropNodeData, type);
    };

    /**
     * 滑块移动
     *
     * @param {IData[]} sliders
     */
    const onSliderMove = (sliders: IData[]) => {
      const nodeData: IGanttNodeData = sliders[0]?.row;
      const newValue = {
        begin: nodeData._beginDataItemValue
          ? dayjs(nodeData._beginDataItemValue).format('YYYY-MM-DD HH:mm:ss')
          : undefined,
        end: nodeData._endDataItemValue
          ? dayjs(nodeData._endDataItemValue).format('YYYY-MM-DD HH:mm:ss')
          : undefined,
      };
      sliderMove.value = true;
      c.modifyNodeTime(nodeData, newValue);
    };

    /**
     * 计算上下文菜单组件配置项集合
     *
     * @param {IDEToolbarItem[]} toolbarItems
     * @param {IGanttNodeData} nodeData
     * @param {MouseEvent} evt
     * @param {IButtonContainerState} menuState
     * @return {*}  {MenuItem[]}
     */
    const calcContextMenuItems = (
      toolbarItems: IDEToolbarItem[],
      nodeData: IGanttNodeData,
      evt: MouseEvent,
      menuState: IButtonContainerState,
    ): MenuItem[] => {
      const result: MenuItem[] = [];
      toolbarItems.forEach(item => {
        if (item.itemType === 'SEPERATOR') {
          result.push({
            divided: 'self',
          });
          return;
        }

        const buttonState = menuState[item.id!] as IButtonState;
        if (buttonState && !buttonState.visible) {
          return;
        }

        // 除分隔符之外的公共部分
        const menuItem: MenuItem = {};
        if (item.showCaption && item.caption) {
          menuItem.label = item.caption;
        }
        if (item.sysImage && item.showIcon) {
          menuItem.icon = <iBizIcon icon={item.sysImage}></iBizIcon>;
        }

        // 界面行为项
        if (item.itemType === 'DEUIACTION') {
          menuItem.disabled = buttonState.disabled;
          menuItem.clickClose = true;
          const { uiactionId } = item as IDETBUIActionItem;
          if (uiactionId) {
            menuItem.onClick = () => {
              c.doUIAction(uiactionId, nodeData, evt, item.appId);
            };
          }
        } else if (item.itemType === 'RAWITEM') {
          const { rawItem } = item as IDETBRawItem;
          if (rawItem) {
            menuItem.label = (
              <iBizRawItem rawItem={item as IDETBRawItem}></iBizRawItem>
            );
          }
        } else if (item.itemType === 'ITEMS') {
          // 分组项绘制子菜单
          if ((item as IDETBGroupItem).detoolbarItems?.length) {
            menuItem.children = calcContextMenuItems(
              (item as IDETBGroupItem).detoolbarItems!,
              nodeData,
              evt,
              menuState,
            );
          }
        }
        result.push(menuItem);
      });

      return result;
    };

    /**
     * 上下文菜单相关
     */
    let ContextMenu: IData;
    c.evt.on('onMounted', () => {
      // 有上下文菜单时加载组件
      if (Object.values(c.contextMenus).length > 0) {
        const importMenu = () => import('@imengyu/vue3-context-menu');
        importMenu().then(value => {
          ContextMenu = value.default;
          if (ContextMenu.default && !ContextMenu.showContextMenu) {
            ContextMenu = ContextMenu.default;
          }
        });
      }
    });

    /**
     * 节点右键菜单点击事件
     *
     * @param {IGanttNodeData} nodeData
     * @param {MouseEvent} evt
     */
    const onNodeContextmenu = async (
      nodeData: IGanttNodeData,
      evt: MouseEvent,
    ) => {
      evt.stopPropagation();
      evt.preventDefault();
      const nodeModel = c.getNodeModel(nodeData._nodeId);
      if (!nodeModel?.decontextMenu) {
        return;
      }
      const contextMenuC = c.contextMenus[nodeModel.decontextMenu.id!];

      if (!contextMenuC.model.detoolbarItems) {
        return;
      }

      // 更新菜单的权限状态
      await contextMenuC.calcButtonState(
        nodeData._deData || (nodeData.srfkey ? nodeData : undefined),
        nodeModel.appDataEntityId,
      );
      const menuState = contextMenuC.state.buttonsState;

      const menus: MenuItem[] = calcContextMenuItems(
        contextMenuC.model.detoolbarItems,
        nodeData,
        evt,
        menuState,
      );
      if (!menus.length) {
        return;
      }

      ContextMenu.showContextMenu({
        x: evt.x,
        y: evt.y,
        customClass: ns.b('context-menu'),
        items: menus,
      });
    };

    const renderNoData = (): VNode | false => {
      // 未加载不显示无数据
      const { isLoaded } = c.state;
      return (
        isLoaded && (
          <iBizNoData
            text={c.model.emptyText}
            emptyTextLanguageRes={c.model.emptyTextLanguageRes}
          ></iBizNoData>
        )
      );
    };

    /**
     * 绘制表格列
     * @param model
     * @param index
     * @returns
     */
    const renderColumn = (model: IDETreeColumn, index: number): VNode => {
      const { caption, codeName, width, headerSysCss, align } = model;
      const columnC = c.columns[codeName!];
      return (
        <x-gantt-column
          label={caption}
          prop={codeName}
          width={width && width > 30 ? width : 30}
          center={align?.toLowerCase() === 'center'}
        >
          {{
            title: ({ label }: IData) => {
              return <div class={headerSysCss?.cssName}>{label}</div>;
            },
            default: ({ row }: IData): VNode | null => {
              const rowState = c.getRowState(row._id);
              if (rowState) {
                const comp = resolveComponent(c.providers[codeName!].component);
                return h(comp, {
                  controller: columnC,
                  row: rowState,
                  key: rowState.data._uuid + codeName,
                });
              }
              return null;
            },
          }}
        </x-gantt-column>
      );
    };

    /**
     * 绘制节点面板
     *
     * @param {IPanel} modelData
     * @param {IData} item
     * @return {*}
     */
    const renderNodePanel = (modelData: IPanel, item: IData) => {
      return (
        <iBizControlShell
          data={item}
          modelData={modelData}
          context={c.context}
          params={c.params}
        ></iBizControlShell>
      );
    };

    /**
     * 绘制节点信息
     *
     * @param {IGanttNodeData} item
     * @return {*}
     */
    const renderNodeInfo = (item: IGanttNodeData) => {
      return (
        <div class={ns.em('slider', 'container')}>
          <div class={ns.em('slider', 'container-title')}>
            <div class='number'>
              {item._icon && (
                <iBizIcon class='icon' icon={item._icon}></iBizIcon>
              )}
              {item._snDataItemValue}
            </div>
            <div class='caption'>{item._text}</div>
          </div>
        </div>
      );
    };

    /**
     * 绘制滑块
     *
     * @return {*}
     */
    const renderSlider = () => {
      return (
        <x-gantt-slider
          allow-link={false}
          move={c.state.sliderDraggable}
          resize-left={c.state.sliderDraggable}
          resize-right={c.state.sliderDraggable}
        >
          {{
            content: ({ row }: { row: IGanttNodeData }): VNode => {
              return (
                <el-popover
                  placement='bottom'
                  width='auto'
                  popper-style={{ 'min-width': '300px' }}
                >
                  {{
                    reference: () => {
                      return (
                        <div
                          class={ns.e('slider')}
                          style={{
                            background: sliderColor.value[row._nodeId],
                          }}
                          onClick={evt => onNodeClick(row, evt)}
                          onDblclick={() => onNodeDbClick(row)}
                          onContextmenu={evt => onNodeContextmenu(row, evt)}
                        ></div>
                      );
                    },
                    default: () => {
                      const panel = findNodeLayoutPanel(row._nodeId);
                      return panel
                        ? renderNodePanel(panel, row._deData!)
                        : renderNodeInfo(row);
                    },
                  }}
                </el-popover>
              );
            },
          }}
        </x-gantt-slider>
      );
    };

    /**
     * 绘制内容
     * @returns
     */
    const renderContent = () => {
      const _columns = columns.value.map((model, index) => {
        return renderColumn(model, index);
      });
      const slider = renderSlider();
      return [..._columns, slider];
    };

    return {
      c,
      ns,
      ganttRef,
      isInited,
      data,
      locale,
      columns,
      onCheck,
      loading,
      ganttStyle,
      onNodeClick,
      onNodeDbClick,
      onNodeExpand,
      onNodeCollapse,
      renderContent,
      onSliderMove,
      renderNoData,
      allowDrop,
      allowDrag,
      handleDrop,
    };
  },
  render() {
    if (!this.isInited) {
      return null;
    }
    return (
      <iBizControlBase
        controller={this.c}
        class={[this.ns.b(), !this.data?.length ? this.ns.m('empty') : '']}
        v-loading={this.loading}
      >
        <x-gantt
          ref='ganttRef'
          data-id='_id'
          data={this.data}
          row-height={46}
          expand-all={false}
          start-key='_beginDataItemValue'
          end-key='_endDataItemValue'
          children='_children'
          leaf='_leaf'
          expand-key='_defaultExpand'
          locale={this.locale}
          draggable={{ level: 'all', draggable: true }}
          allow-drop={this.allowDrop}
          allow-drag={this.allowDrag}
          onNodeDrop={this.handleDrop}
          showCheckbox={!this.c.state.singleSelect}
          onNodeExpand={this.onNodeExpand}
          onNodeCollapse={this.onNodeCollapse}
          onRowClick={this.onNodeClick}
          onRowDblClick={this.onNodeDbClick}
          onRowChecked={this.onCheck}
          onMoveSlider={this.onSliderMove}
          primaryColor={this.ganttStyle.primaryColor}
          headerStyle={{ textColor: this.ganttStyle.textColor }}
        >
          {{
            default: () => {
              return this.renderContent();
            },
            empty: () => {
              return this.renderNoData();
            },
          }}
        </x-gantt>
      </iBizControlBase>
    );
  },
});
